package cn.ulyer.core.secure.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.ulyer.common.exception.TokenInvalidException;
import cn.ulyer.common.utils.JwtUtil;
import cn.ulyer.common.utils.WebUtils;
import cn.ulyer.common.properties.LoginProperties;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;

public abstract class AbstractTokenService implements TokenService{

    private static final Logger log = LoggerFactory.getLogger(AbstractTokenService.class);


    protected final static String BEARER = "Bearer ";

    protected final static String ACCESS_TOKEN = "access_token";

    @Autowired
    protected LoginProperties loginProperties;


    @Override
    public abstract Object store(Object token, Authentication authentication) ;



    @Override
    public Object readToken(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if(StrUtil.isBlank(token)){
            return request.getParameter(ACCESS_TOKEN);
        }
        return token.replace(BEARER,"");
    }

    @Override
    public Object generatorToken(HttpServletRequest request) {
        Map<String,Object> map = MapUtil.newHashMap();
        map.put("ip", request.getRemoteAddr());
        map.put("tokenKey", UUID.fastUUID().toString());
        return JwtUtil.generatorToken(loginProperties.getPrivateKey(),map);
    }

    @Override
    public Authentication authenticate(Object token) throws AuthenticationException {
        String jwt = (String) token;
        if(StrUtil.isBlank(jwt)){
            throw new TokenInvalidException("缺少token");
        }
        Claims claims = JwtUtil.parseClaims(loginProperties.getPrivateKey(),jwt);
        HttpServletRequest request = WebUtils.getRequest();
        String requestIp = request.getRemoteAddr();
        if( !claims.get("ip").equals(requestIp)){
            throw new InvalidRequestException("异常ip请求");
        }
        Date signDate =  claims.getIssuedAt();
        LocalDateTime invalidTime = LocalDateTime.ofInstant(signDate.toInstant(), ZoneId.systemDefault()).plusHours(loginProperties.getTokenExpire());
        log.info("token invalid time :{}",DateUtil.format(invalidTime,"yyyy-MM-dd HH:mm:ss"));
        if(invalidTime.isBefore(LocalDateTime.now())){
            throw new TokenInvalidException("token过期");
        }
        return obtainAuthentication(token);
    }

    protected abstract Authentication obtainAuthentication(Object key);

}
